package com.cf.mvp.mvp;


import androidx.lifecycle.Lifecycle;

import com.cf.mvp.rx.LifecycleToRxSubject;
import com.cf.mvp.rx.LifecycleTransformer;
import com.cf.mvp.rx.RxEventSubject;
import com.cf.mvp.rx.RxLifecycle;
import com.cf.mvp.tool.LogUtils;

import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;

import io.reactivex.subjects.BehaviorSubject;

/**
 * @author yangji
 * basePresenter 用于处理核心内容创建、回收
 */
public abstract class BasePresenter<M extends IModel, V extends IBaseView> implements IPresenter<V>, RxEventSubject, ILifecycle {


    private LifecycleToRxSubject subject = LifecycleToRxSubject.create();

    @Override
    public BehaviorSubject<Lifecycle.Event> getSubject() {
        return subject.getSubject();
    }

    private M mModel;
    private WeakReference<V> mView;
    private V mProxyView;

    @Override
    @SuppressWarnings({"unchecked"})
    public void bindView(V view) {
        LogUtils.d("统计:bindView" + view.hashCode() + " " + this.hashCode());

        mView = new WeakReference<>(view);
        mProxyView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), (proxy, method, args) -> {
            if (mView == null || mView.get() == null) {
                LogUtils.d("统计：", BasePresenter.this.getClass().getSimpleName(), "调用方法 ", method.getName(), " MvpView 已经销毁");
                return null;
            }
            LogUtils.d("统计：", BasePresenter.this.getClass().getSimpleName(), "调用方法 ", method.getName(), "执行前");
            Object object = method.invoke(mView.get(), args);
            LogUtils.d("统计：", BasePresenter.this.getClass().getSimpleName(), "调用方法 ", method.getName(), "执行后");
            return object;
        });
        //延后初始化 可以放在构造方法
        initModel();
    }

    /**
     * 通过反射获取model
     */
    @SuppressWarnings({"unchecked"})
    private void initModel() {
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        LogUtils.d("###########", "initModel: " + this.getClass().getSimpleName(), " ", hashCode() + "");
        if (type != null) {
            Type[] types = type.getActualTypeArguments();
            if (((Class) types[0]).isAssignableFrom(IModel.class)) {
                //当前不适用Model 不推荐方式 为了方式 乱使用报错
                mModel = (M) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{(Class) types[0]}, new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //当前不适用Model不错任何事情
                        if ("bindPresenter".equals(method.getName()) && args.length == 1) {
                            //这里是绑定操作
                            return null;
                        }
                        return null;
                    }
                });
                return;
            }
            try {

                mModel = (M) ((Class<?>) types[0]).newInstance();
                mModel.bindPresenter(this);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }

    protected V getMvpView() {
        return mProxyView;
    }

    protected M getModel() {
        return mModel;
    }

    /**
     * 有了生命周期 其实可以不需要这个东西
     */
    @Override
    public void unBindView() {
        if (null != mView) {
            mView.clear();
            mView = null;
        }
    }

    @Override
    public void onCreate() {
        LogUtils.d("生命周期", getClass().getName() + hashCode(), "onCreate");
        subject.onCreate();
    }

    @Override
    public void onStart() {
        LogUtils.d("生命周期", getClass().getName() + hashCode(), "onStart");
        subject.onStart();
    }

    @Override
    public void onResume() {
        LogUtils.d("生命周期", getClass().getName() + hashCode(), "onResume");
        subject.onResume();
    }

    @Override
    public void onPause() {
        LogUtils.d("生命周期", getClass().getName() + hashCode(), "onPause");
        subject.onPause();
    }

    @Override
    public void onStop() {
        LogUtils.d("生命周期", getClass().getName() + hashCode(), "onStop");
        subject.onStop();
    }

    @Override
    public void onDestroy() {
        LogUtils.d("生命周期", getClass().getName() + hashCode(), "onDestroy");
        subject.onDestroy();
        unBindView();
    }

    protected <T, R> LifecycleTransformer<T> bindEvent() {
        return RxLifecycle.bindEvent(getSubject(), Lifecycle.Event.ON_DESTROY);
    }

    protected <T, R> LifecycleTransformer<T> bindEvent(Lifecycle.Event event) {
        return RxLifecycle.bindEvent(getSubject(), event);
    }

}